feat: complex playground — explore complex functions f(z) on any image#14
Merged
Conversation
A new "playground" view (5th tool-rail button) that warps the loaded image (gallery picture, bundled sample, or grid/polar pattern) through a chosen complex function f(z), GeoGebra-style: - Curated preset shelf: identity, z², zⁿ, 1/z, Möbius, Joukowski, exp, log, Escher zᵃ, sin. One GLSL branch each (uber-shader), mirrored on CPU for the no-WebGL2 fallback. Per-preset analytic f' drives mip-LOD anti-aliasing. - Live, schema-generated controls (sliders / complex number fields) + reset; the active formula is rendered live and updates as you tweak. - Hand-drag adds a complex constant c to the formula, with a toggle for domain f(z+c) vs output f(z)+c composition; wheel zooms. - Draggable on-canvas handles for a preset's zero/pole (Möbius), plus an origin cross and unit-circle overlay. - Fill modes (tile / clamp / mirror) so out-of-image samples never go black. Its own light complex frame (origin + scale), independent of the Droste doc.rect; reuses doc.image and the existing image-source paths. Verified live (no console errors); 18 unit tests cover the preset math + formula text. Shaping doc: shaping/complex-playground-shaping.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Two more "cool" presets: tan(z) (periodic, poles) and sin(1/z) (essential singularity — dense kaleidoscope at the origin). Shader gains an explicit fallback branch. - Fix the Möbius derivative sign: f'(z) = k(z0−z∞)/(z−z∞)². Only fed the AA footprint (|f'|), so no visible change, but it was wrong. Locked by a test. Verified live (sin(1/z) renders, no console errors); 22 preset tests (44 total). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- playgroundDirty() now also returns true when a preset parameter differs from its default (a slider nudge or dragged Möbius zero/pole), so the reset button enables on param-only edits — not just pan/zoom. Verified live. - PlaygroundStage falls back to the CPU path when WebGL2 init throws after detectCapabilities reported it available (glInitFailed flag), instead of the render guard returning forever and leaving the stage blank. Both P2 findings from codex review. Tests/typecheck/build green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A new complex playground view (5th tool-rail button, the graph glyph) that warps the loaded image — a gallery picture, the bundled sample, or the generated grid/polar patterns — through a chosen complex function
f(z), GeoGebra-style. Built from a shaping session (shaping/complex-playground-shaping.md).Feature (
feat(playground))z²,zⁿ,1/z, Möbiusk(z−z₀)/(z−z∞), Joukowski,exp,log, Escherzᵃ,sin,tan,sin(1/z). Each carries an analyticf'for mip-LOD anti-aliasing.cto the formula, with a toggle for domainf(z+c)vs outputf(z)+c; wheel zooms.It runs on its own complex frame (origin + scale), independent of the Droste
doc.rect; it only borrowsdoc.imageand the existing image-source paths (DropZone sample/patterns, Gallery).New files:
src/lib/render/playground/{presets.ts,shader.frag.glsl,gl.ts,cpu.ts},src/lib/ui1/playground.svelte.ts,src/components/ui1/{PlaygroundStage,PlaygroundControls}.svelte,tests/render/playground-presets.test.ts. Wired intostate.svelte.ts(ViewMode),ToolRail.svelte,UiVariant1.svelte,icons.ts.Test Coverage
tests/render/playground-presets.test.ts— 22 tests covering presetf(z)values, the Möbiusf'sign, uniform packing, and live-formula text in both pan modes. Suite: 22 → 44 tests total, all passing.Coverage is on the pure preset library (the math). The Svelte components and GL/CPU renderers are verified by live browser QA below (the
.svelte.tsstate + GLSL can't run under node/vitest).Pre-Landing Review
Inline checklist pass: no SQL/data/LLM trust-boundary surface; no secrets; resource cleanups present (
dispose,cancelAnimationFrame,ResizeObserver.disconnect); reactivity reads inputs synchronously. One self-caught nit (Möbiusf'sign, AA-only) fixed in commit 2.Adversarial Review (Codex, cross-model)
Codex flagged 2 × P2 (no P1):
playgroundDirty()now includes param drift). Verified live.glInitFailedflips to the CPU path).Verification (live, via headless browser)
No console errors across: Escher
zᵃ(spiral),1/z(inversion), Möbius (handles + correct formula),sin(1/z)(essential-singularity kaleidoscope), drag→cupdating the formula, mirror fill, reset enabling after a param edit, dragging the Möbius zero. Mobile (390×844) layout verified — control strip wraps, tool rail becomes a bottom bar.Plan Completion
All shaping slices V1–V5 landed (see
shaping/complex-playground-shaping.md). Conformal coordinate grid was intentionally dropped (clutter vs. the image warp itself); origin cross + unit circle kept.Notes
VERSION/CHANGELOG.md, so no version bump (consistent with prior PRs).Test plan
npm run test— 44 passingnpm run check— 0 errorsnpm run build— clean🤖 Generated with Claude Code
Staging: https://silvio-tententoon-complex-playground.pgs.sh/ — open the app, then click the 5th tool-rail button (graph glyph) to enter the complex playground.